package com.clp.protocol.modbus_tcp.client.pipeline.handler;

import com.clp.protocol.modbus_tcp.client.MasterImpl;
import com.clp.protocol.modbus_tcp.client.ModbusClient;
import com.clp.protocol.modbus_tcp.client.pipeline.DuplexMasterHandler;
import com.clp.protocol.modbus_tcp.mb_frame.ReqMbFrm;
import com.clp.protocol.modbus_tcp.mb_frame.RespMbFrm;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.ScheduledFuture;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ControlMasterHandler extends DuplexMasterHandler {
    private List<ScheduledFuture<?>> scheduledFutures = new ArrayList<>();

    @Override
    public void whenActiveWithoutMaster(ChannelHandlerContext ctx) throws Exception {
        passActive(ctx);
    }

    @Override
    public void whenRecvingMbFrm(ChannelHandlerContext ctx, RespMbFrm respMbFrm) {
        if (respMbFrm == null) return;
        MasterImpl masterImpl = (MasterImpl) master();

        // 检查和更新所有状态
        respMbFrm = masterImpl.updateStatesByRecving(respMbFrm);
        if (respMbFrm == null) return;

        // 执行回调
        masterImpl.handleRecvMbFrmCallbacks(respMbFrm);
        passRecvingMbFrm(ctx, respMbFrm);
    }

    @Override
    public void whenSendingMbFrm(ChannelHandlerContext ctx, ReqMbFrm reqMbFrm, ChannelPromise promise) {
        if (reqMbFrm == null) return;

        MasterImpl masterImpl = (MasterImpl) this.master();

        // 检查和更新所有状态
        reqMbFrm = masterImpl.updateStatesBySending(reqMbFrm);
        if (reqMbFrm == null) return;

        // 发送前处理：更新序号
        masterImpl.addSendSeqCircularly();

        passSendingMbFrm(ctx, reqMbFrm, promise);
    }

    @Override
    public void whenInActive(ChannelHandlerContext ctx) throws Exception {
        // 取消所有循环任务
        for (ScheduledFuture<?> scheduledFuture : scheduledFutures) {
            scheduledFuture.cancel(true);
        }

        // 从通道列表中删除（如果有）
        ModbusClient.get().disconnect(master(), false);

        passInActive(ctx);
    }

    @Override
    public void whenExceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        passExceptionCaught(ctx, cause);
    }
}
